﻿package Leophy.text {
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.text.Font;
	import flash.utils.describeType;
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;

	import Leophy.Interfaces.IAsynCallBack;
	import Leophy.Interfaces.IFont;
	import Leophy.Interfaces.ISay;
	import Leophy.Net.XMLLoader;
	import Leophy.utils.Debug;

	/**
	 * ...
	 * @author TOPHY
	 */
	public class MyFont extends Font implements IEventDispatcher,ISay, IFont {

		private static var _instance : MyFont;

		/**
		 * MyFont 的单例
		 * @return
		 */
		public static function get Ins() : MyFont {
			if (_instance == null) {
				_instance = new MyFont();
			}
			return _instance;
		}

		private var FontIndexURL : String;
		private var FontFolderURL : String;
		private var fontxmlurl : XMLLoader;
		private var fontList : Object;
		private var fontlistLoaded:Boolean = false;
		public function get isFontListLoaded():Boolean {
			return fontlistLoaded;
		}
		//private var loader:Loader;
		private var callbackList : Object;

		//private var embeding:Boolean=false;
		
		/**
		 * 判断是否为已嵌入的字体
		 * @param	fontName 字体名
		 * @return
		 */
		public function IsEmbed(fontName : String) : Boolean {
			var f_ar : Array = enumerateFonts(false);
			for (var i : uint = 0;i < f_ar.length; i++) {
				//trace(f_ar[i].fontName ,fontName)
				if (f_ar[i].fontName == fontName || f_ar[i].toString().indexOf(fontName) > 0) return true;
			}
			return false;
		}

		/**
		 * 根据显示名，返回正确的字体类
		 * @param	fontName 字体显示名
		 * @return
		 */
		public function GetEmbedFontByName(fontName : String) : Font {
			var f_ar : Array = enumerateFonts(false);
			for (var i : uint = 0;i < f_ar.length; i++) {
				//trace(f_ar[i].fontName ,fontName)
				if (f_ar[i].fontName == fontName || f_ar[i].toString().indexOf(fontName) > 0) return f_ar[i];
			}
			return null;
		}

		/**
		 * 字体类，带有加载字体的功能
		 * @param	fontsFolderUrl 字体资源文件夹位置
		 * @param	fontListIndexXMLUrl 字体资源文件索引文件名
		 */
		public function MyFont(fontsFolderUrl : String = null,fontListIndexXMLUrl : String = "fontindex.xml") {
			if (fontListIndexXMLUrl == null || fontListIndexXMLUrl == "") {
				fontListIndexXMLUrl = "fontindex.xml";
			}
			callbackList = new Object();
			//loadFontList(fontsFolderUrl, fontListIndexXMLUrl);
			_eventHolder = new Object();
		}

		/**
		 * 加载字体列表
		 * @param	folder 字体资源文件夹位置
		 * @param	url 字体资源文件索引文件名
		 */
		public function loadFontList(folder : String, url : String = "fontindex.xml") {
			if (url == null || url == "") {
				url = "fontindex.xml";
			}
			FontIndexURL = url;
			FontFolderURL = folder;
			if (fontxmlurl == null) {
				fontxmlurl = new XMLLoader();
				fontxmlurl.addEventListener(XMLLoader.COMPLETE_XML, onloadedfontListXML);
				fontxmlurl.addEventListener(IOErrorEvent.IO_ERROR, onERRORloadingfontListXML);
			}
			var urlrequest : URLRequest = new URLRequest(folder + url);
			fontxmlurl.load(urlrequest);
			fontlistLoaded = false;
		}

		/**
		 * 异步加载字体并嵌入
		 * @param	fontName
		 */
		public function BeginEmbedFont(fontName : String, calltype : String, callBackObject : IAsynCallBack, data : *) {
			
			//trace("BeginEmbedFont", fontName,"list="+fontList[fontName]);
			if (fontName == null || fontName == "") {
				callBackObject.EndAsynCallBack(calltype, [data, false]);
				return;
			}
			if (IsEmbed(fontName)) {
				callBackObject.EndAsynCallBack(calltype, [data, true]);
				return;
			}
			if (!IsEmbed(fontName) && fontList[fontName] == null) {
				callBackObject.EndAsynCallBack(calltype, [data,false]);
			}
			else {
				//trace(fontList[fontName].url)
				var loader : Loader;
				if (callbackList[fontName] == null) {
					callbackList[fontName] = new Array();
					loader = new Loader();
					var urlreqeust : URLRequest = new URLRequest(FontFolderURL + fontList[fontName].url);
					loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadedFont);
					loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoadingFont);
					loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onERRORonLoadingFont);
					loader.load(urlreqeust);
				}else {
					loader = callbackList[fontName][0].ld;
				}
				callbackList[fontName].push({fontClassName:fontList[fontName].className, type:calltype, obj:callBackObject, data:data, ld:loader});
			}
		}

		private function onERRORonLoadingFont(ev : IOErrorEvent) : void {
			ev.text = "Error on loading Font.\r" + ev.text;
			say(ev.text);
			dispatchEvent(ev);
		}

		private function onLoadedFont(ev : Event) : void {
			//trace("----===========");
			for (var fontName in callbackList) {
				//trace(fontName,callbackList[fontName])
				if (ev.target == callbackList[fontName][0].ld.contentLoaderInfo) {
					var myf : Class = ev.target.applicationDomain.getDefinition(callbackList[fontName][0].fontClassName) as Class;
					//trace("befor embed", myf==null);
					Font.registerFont(myf);
					
					//trace("embed:", Font.enumerateFonts(false));
					/*
					for (var fi = 0; fi < Font.enumerateFonts(false).length; fi++) {
					trace("   -e:",Font.enumerateFonts(false)[fi].fontName)
					}
					 */
					for (var i : uint = 0;i < callbackList[fontName].length; i++) {
						
						var cbobj : IAsynCallBack = IAsynCallBack(this.callbackList[fontName][i].obj);
						var _type : String = this.callbackList[fontName][i].type;
						var _data : Array = [this.callbackList[fontName][i].data, true];
						cbobj.EndAsynCallBack(_type, _data);
						
						//trace("----",cbobj, _type, _data);
					}
					delete this.callbackList[fontName];
					return;
				}
			}
		}

		private function onLoadingFont(ev : ProgressEvent) : void {
			//say(LoaderInfo(ev.target).url);
			say("loading font[" + ev.bytesLoaded + "/" + ev.bytesTotal + "]");
			dispatchEvent(ev);
		}

		private function onERRORloadingfontListXML(ev : IOErrorEvent) : void {
			ev.text = "Error on Loading Font index file.\r" + ev.text;
			say(ev.text);
			dispatchEvent(ev);
		}

		private function onloadedfontListXML(ev : Event) : void {
			var xml : XML = ev.target.data;
			fontList = new Object();
			for (var i : uint = 0;i < xml.font.length(); i++) {
				fontList[xml.font[i].@fontName.toString()] = { 
					fontName:xml.font[i].@fontName.toString(), url:xml.font[i].@url.toString(), className:xml.font[i].@className.toString()
					};
			}
			
			Debug.traceObj(fontList);
			say("Font list loaded!");
			fontlistLoaded = true;
			this.dispatchEvent(new Event(Event.COMPLETE));
		}

		////====================================================================    EventDispatcher实现
		private var _eventHolder : Object;

		public function addEventListener(type : String, listener : Function, useCapture : Boolean = false, priority : int = 0, useWeakReference : Boolean = false) : void {
			if (_eventHolder[type] == null) {
				_eventHolder[type] = new Dictionary();
			}
			_eventHolder[type][listener] = listener;
		}

		public function dispatchEvent(event : Event) : Boolean {
			if (_eventHolder[event.type] == null) return false;
			
			var dt : Dictionary = _eventHolder[event.type];
			for each(var l in dt) {
				l(event);
			}
			return true;
		}

		public function hasEventListener(type : String) : Boolean {
			if (_eventHolder[type] == null) return false;
			var dt : Dictionary = _eventHolder[type];
			return dt != null;
		}

		public function removeEventListener(type : String, listener : Function, useCapture : Boolean = false) : void {
			if (_eventHolder[type] == null) return;
			var dt : Dictionary = _eventHolder[type];
			delete dt[listener];
		}

		public function willTrigger(type : String) : Boolean {
			return hasEventListener(type);
		}

		/* INTERFACE Leophy.Interfaces.ISay */
		public function say(o : *) : void {
			trace("MYFont:", o.toString());
		}
	}
}